Skip to content

introduce dirty list to dataflow #51900

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 3, 2018
Merged

Conversation

PramodBisht
Copy link
Contributor

@nikomatsakis my naive implementation never worked, So, I decided to implement using work_queue data structure. This PR also includes your commits from nll-liveness-dirty-list branch. Those commits should not visible once your branch is merged.

r? @nikomatsakis

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jun 29, 2018
@PramodBisht PramodBisht requested a review from nikomatsakis June 29, 2018 13:40
@rust-highfive

This comment has been minimized.

builder.propagate_bits_into_graph_successors_of(
in_out, &mut self.changed, (mir::BasicBlock::new(bb_idx), bb_data));
while let Some(bb) = dirty_queue.pop() {
let bb_data: &BasicBlockData<'tcx> = &mir.basic_blocks()[*bb];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

easier: &mir[bb]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, no type annotation is needed here (but it doens't hurt)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done!

in_out, &mut self.changed, (mir::BasicBlock::new(bb_idx), bb_data));
while let Some(bb) = dirty_queue.pop() {
let bb_data: &BasicBlockData<'tcx> = &mir.basic_blocks()[*bb];
let builder = &mut self.builder;
Copy link
Contributor

@nikomatsakis nikomatsakis Jun 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

odd indentation; and why introduce let?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed indentation, let is introduced in diff because of bad indentation. Anyway, I have removed the dependency of that builder variable.

{
let sets = builder.flow_state.sets.for_block(bb_idx);
debug_assert!(in_out.words().len() == sets.on_entry.words().len());
in_out.clone_from(sets.on_entry);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nnethercote noticed that this name (clone_from) was causing problems (it shadows clone_from from the Clone trait, and sometimes that gets called instead, which is less efficient). They have a PR to fix it, but in the meantime, do this, which will ensure we're calling the method we want:

IdxSet::clone_from(in_out, sets.on_entry);

that said, I think we will be calling the correct one here anyway, given the type of in_out.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done!

in_out.subtract(sets.kill_set);
}
builder.propagate_bits_into_graph_successors_of(
in_out, &mut self.changed, (mir::BasicBlock::new(bb_idx), bb_data), dirty_queue);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need the changed flag anymore -- the only bit that matters is if the dirty queue is empty.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed changed flag.

let entry_set = self.flow_state.sets.for_block(bb.index()).on_entry;
let set_changed = bitwise(entry_set.words_mut(),
in_out.words(),
&self.flow_state.operator);
if set_changed {
*changed = true;
for row in self.mir.basic_blocks()[*bb].terminator().successors(){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, bb here is already the successor -- we just need to do

dirty_list.insert(*bb);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed!

@@ -877,13 +885,18 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation
fn propagate_bits_into_entry_set_for(&mut self,
in_out: &IdxSet<D::Idx>,
changed: &mut bool,
bb: &mir::BasicBlock) {
bb: &mir::BasicBlock,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pre-existing, but I think we should change the type of bb here to bb: mir::BasicBlock -- the & is silly

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed !

@rust-highfive

This comment has been minimized.

Copy link
Contributor

@nikomatsakis nikomatsakis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks functionally correct! Exciting. I left some nits.

propcx.changed = false;
propcx.walk_cfg(&mut temp);
}
let mut dirty_queue: WorkQueue<mir::BasicBlock> =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: we should probably move the dirty_queue creation into walk_cfg; or else merge walk_cfg and this method. But anyway, doesn't matter.

builder.propagate_bits_into_graph_successors_of(
in_out, &mut self.changed, (mir::BasicBlock::new(bb_idx), bb_data));
self.builder.propagate_bits_into_graph_successors_of(
in_out, (mir::BasicBlock::new(bb.index()), bb_data), dirty_queue);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: mir::BasicBlock::new(bb.index()) is just bb =)

mir::TerminatorKind::Goto { ref target } |
mir::TerminatorKind::Assert { ref target, cleanup: None, .. } |
mir::TerminatorKind::Yield { resume: ref target, drop: None, .. } |
mir::TerminatorKind::Drop { ref target, location: _, unwind: None } |
mir::TerminatorKind::DropAndReplace {
ref target, value: _, location: _, unwind: None
} => {
self.propagate_bits_into_entry_set_for(in_out, changed, target);
self.propagate_bits_into_entry_set_for(in_out, *target, dirty_list);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: instead of *target here, we can remove the ref from ref target in the patterns above

{
match bb_data.terminator().kind {
mir::TerminatorKind::Return |
mir::TerminatorKind::Resume |
mir::TerminatorKind::Abort |
mir::TerminatorKind::GeneratorDrop |
mir::TerminatorKind::Unreachable => {}

mir::TerminatorKind::Goto { ref target } |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: i.e., change this to target not ref target (see below)

}
mir::TerminatorKind::Assert { ref target, cleanup: Some(ref unwind), .. } |
mir::TerminatorKind::Drop { ref target, location: _, unwind: Some(ref unwind) } |
mir::TerminatorKind::DropAndReplace {
ref target, value: _, location: _, unwind: Some(ref unwind)
} => {
self.propagate_bits_into_entry_set_for(in_out, changed, target);
self.propagate_bits_into_entry_set_for(in_out, *target, dirty_list);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: same here...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(and all the other cases below)

@nikomatsakis
Copy link
Contributor

@bors try

Local perf runs suggested this was not a win.

@bors
Copy link
Collaborator

bors commented Jun 30, 2018

⌛ Trying commit 2a5c3c469680e333ec06845b725cd07aaf1fae45 with merge ddc3f99bad126b9f5755177d82f651d8f91d8683...

@bors
Copy link
Collaborator

bors commented Jun 30, 2018

☀️ Test successful - status-travis
State: approved= try=True

@lqd
Copy link
Member

lqd commented Jun 30, 2018

@Mark-Simulacrum can we schedule a perf run for this PR please ? :)

@Mark-Simulacrum
Copy link
Member

Perf run is scheduled.

@nikomatsakis
Copy link
Contributor

OK, the perf results are quite interesting:

http://perf.rust-lang.org/compare.html?start=87ecf5442ced38a6253e670dd6d87c0c334b21fb&end=ddc3f99bad126b9f5755177d82f651d8f91d8683&stat=instructions%3Au

It seems like my local measurement was correct but misleading -- clap-rs did get slower (by 2.5%) but lots of stuff is way faster!

@nikomatsakis nikomatsakis changed the title [WIP] introduce dirty list to dataflow introduce dirty list to dataflow Jul 2, 2018
@nikomatsakis nikomatsakis added S-blocked Status: Blocked on something else such as an RFC or other implementation work. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 2, 2018
@nikomatsakis
Copy link
Contributor

This is r=me but:

@rust-highfive

This comment has been minimized.

debug_assert!(in_out.words().len() == sets.on_entry.words().len());
in_out.overwrite(sets.on_entry);
IdxSet::clone_from(in_out, sets.on_entry);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be overwrite

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done!

@nikomatsakis
Copy link
Contributor

@bors r+

@bors
Copy link
Collaborator

bors commented Jul 2, 2018

📌 Commit 09df6a0 has been approved by nikomatsakis

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-blocked Status: Blocked on something else such as an RFC or other implementation work. labels Jul 2, 2018
@bors
Copy link
Collaborator

bors commented Jul 3, 2018

⌛ Testing commit 09df6a0 with merge fb97bb5...

bors added a commit that referenced this pull request Jul 3, 2018
introduce dirty list to dataflow

@nikomatsakis my naive implementation never worked, So, I decided to implement using `work_queue` data structure. This PR also includes your commits from `nll-liveness-dirty-list` branch. Those commits should not visible once your branch is merged.

r? @nikomatsakis
@bors
Copy link
Collaborator

bors commented Jul 3, 2018

☀️ Test successful - status-appveyor, status-travis
Approved by: nikomatsakis
Pushing fb97bb5 to master...

@bors bors merged commit 09df6a0 into rust-lang:master Jul 3, 2018
@michaelwoerister
Copy link
Member

These are some pretty great performance wins for some crates even in the non-NLL case! 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants